package org.hagopa.games.moneypool.network;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;


import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hagopa.games.moneypool.msgs.CommandsEnum;
import org.hagopa.games.moneypool.msgs.Message;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.ClientIntro;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.PlayerType;
import org.hagopa.games.moneypool.msgs.utils.ClientSession;
import org.hagopa.games.moneypool.utils.UsefulUtils;

public class NetClientHandler implements IClientHandler{
	
	private SocketChannel schannel = null;
	private ClientStatus status = null;
	private long sessionId = 0;
	
	private int clientVersion = 0;
	private int gameId = 0;
	private String hashKey = null;

	private String clientIP = null;
	private ClientSession csess = null;
	
	private Message lastClientMsg = null;
	private Message Msg4Client = null;
	private String whereRegistered = "";
	//TODO for prevent flood!!!! if lastMessage similar to new Message, and lastMsgTime < x sec => drop
	private long lastMsgTime = 0;  
	
	public long getLastMsgTime() {
		return lastMsgTime;
	}
	public void setLastMsgTime(long lastMsgTime) {
		this.lastMsgTime = lastMsgTime;
	}

        public void setHashKey(String hkey)
        {
            this.hashKey = hkey;
        }
	public NetClientHandler(SocketChannel csocket)
	{
		if(csocket.isConnected())
		{
			try {
				schannel = csocket;
				this.clientIP = csocket.socket().getInetAddress().getHostName();
				schannel.configureBlocking(false);
				setStatus(ClientStatus.CONNECTED);
				} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	public String getClientIP() {
		return clientIP;
	}
        public String getHashKey()
        {
            return this.hashKey;
        }
	public void setClientIP(String clientIP) {
		this.clientIP = clientIP;
	}
	public void response()
	{
		System.out.println("Select Key registered in :" + whereRegistered);
		if(null == lastClientMsg)
			return;
		System.out.println("[NetClientHandler](response) - Message before response: Command - " + lastClientMsg.getCommand());
		Message reply = new Message();

		reply.setClientId(lastClientMsg.getClientId());
		reply.setSessionId(lastClientMsg.getSessionId());
		if(CommandsEnum.INTRO == lastClientMsg.getCommand())
		{
			if(null == lastClientMsg.getContentHandler())
				return;
			else
			{
				this.clientVersion = ((ClientIntro)lastClientMsg.getContentHandler()).getClVersion();
				System.out.println("[NetClientHandler](response) - Client Version: " + this.clientVersion);
				this.gameId = ((ClientIntro)lastClientMsg.getContentHandler()).getGameId();
				System.out.println("[NetClientHandler](response) - Client should be connected to Game No: " + this.gameId);
			}
			System.out.println("[NetClientHandler](response) - Received Content Sz:" + lastClientMsg.getContentSz());
			
			reply.setCommand(CommandsEnum.ACCEPT);
			PlayerType pt = new PlayerType();
			pt.setType(1);
			pt.setPlayerId(1);
			reply.setContentSz(8);
			reply.setContentHandler(pt);
                        
			setStatus(ClientStatus.AFTER_HANDSHAKE);
			
		}
		else if(CommandsEnum.DISCONNECT == lastClientMsg.getCommand())
		{
			setStatus(ClientStatus.DISCONNECTED);
			try {
				this.schannel.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return;
		}
		else
                {
                    setStatus(ClientStatus.DISCONNECTED);
			try {
				this.schannel.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			return;
                }
		System.out.println("\n------------------\n[NetClientHandler](response) - Sending Command: " 
							+ reply.getCommand().getName() + 
							"\n---------------------\n");
		byte[] msg =  reply.marshall();
		sendMsg(msg);
		
		
	}
	public SocketChannel getChannel(){
		
		return this.schannel;
	}
	
	
	public byte[] getMsg() {
		
		byte [] data = new byte[1024];
		ByteBuffer dst =  ByteBuffer.allocate(1024);
		String date = null;
		int bytesNo = 0;
                
		try {
			if(this.schannel.isConnected())
				bytesNo = this.schannel.read(dst);
			else
				return null;
			//Date time = new Date(0);
//			if((time.getTime() - this.lastMsgTime ) > 60)
//				this.lastMsgTime = time.getTime();
//			else
//				return null;
		} catch (IOException e) {
			System.out.println("[NetClientHandler](getMsg) - Disconnected");
			return null;
		}
		if(bytesNo < 0 )
		{
			System.out.println("[NetClientHandler](getMsg) - Disconnected [ nothing to read ]");
			return null;
		}
		dst.rewind();
		System.out.println("Select Key registered in :" + whereRegistered);
		dst.get(data, 0, data.length);
		this.lastClientMsg = new Message();
                this.lastClientMsg.setClientIP(this.clientIP);
                this.lastClientMsg.setHashKey(this.hashKey);
		if(this.lastClientMsg.unmarshall(data) == true)
		{
                    	System.out.println("[NetClientHandler](getMsg)\n===========MSG============\n");
			System.out.println("[NetClientHandler](getMsg) - Received Last Msg: ");
			System.out.println("[NetClientHandler](getMsg) - ClientId: " + this.lastClientMsg.getClientId());
			System.out.println("[NetClientHandler](getMsg) - SessionId: " + this.lastClientMsg.getSessionId());
			System.out.println("[NetClientHandler](getMsg) - Command: "+ this.lastClientMsg.getCommand().getName());
			System.out.println("\n==========END MSG==========\n");
			if(CommandsEnum.INTRO == lastClientMsg.getCommand())
			{
				this.gameId = ((ClientIntro)lastClientMsg.getContentHandler()).getGameId();
			}
			return data;
		}
		else
		{
			System.out.println("[NetClientHandler](getMsg) - Failed to recognize Command");
					return null;
		}
	}
		
	public boolean sendMsg(byte[] msg) {
		// TODO Auto-generated method stub
		
		long nbytes = 0;
		ByteBuffer bb =  ByteBuffer.wrap(msg);
                long toWrite = bb.remaining();
		bb.rewind();
               // bb.flip();
		System.out.println("Select Key registered in :" + whereRegistered);
		try {
			if(this.schannel.isOpen() && this.schannel.isConnected())
			{
                            while (nbytes != toWrite)
                            {

				nbytes += schannel.write(bb);
				System.out.println("[NetClientHandler](sendMsg) - [msg:"+ msg + "] Written to socket " + nbytes + " bytes");
                                try {
                                        Thread.sleep(200);
                                    } catch (InterruptedException ex) {
                                        Logger.getLogger(NetClientHandler.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                            }
			}
			else
			{
				System.out.println("[NetClientHandler](sendMsg) - Channel is not opened");
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public  ClientStatus getStatus() {
		return this.status;
	}

	public  void setStatus(ClientStatus status) {
		System.out.println("[NetClientHandler]Set New Status: " + status.name());
		this.status = status;
	}
    
 
	public int getClientId() {
		if(null == lastClientMsg)
		{
			System.out.println("[NetClientHandler](getClientId) - No Last Msg!!!");
			return -1;
		}
		lastClientMsg.getClientId();
		return lastClientMsg.getClientId();
	}
	/*  @TPAZ -  unnecessary:  
	public void setClientId(int clientId) {
		this.clientId = clientId;
	}
*/
	public long getSessionId() {
		return sessionId;
	}
	public void setSessionId(long sessionId) {
		this.sessionId = sessionId;
	}
	public Message getLastClientMsg() {
		return lastClientMsg;
	}
	public void setLastClientMsg(Message lastClientMsg) {
		this.lastClientMsg = lastClientMsg;

	}
	public Message getMsg4Client() {
		return Msg4Client;
	}
	public void setMsg4Client(Message msg4Client) {
		this.Msg4Client = msg4Client;
                this.Msg4Client.setClientIP(this.clientIP);
                this.Msg4Client.setHashKey(this.hashKey);
	}
	public ClientSession getCsess() {
		return csess;
	}
	public void setCsess(ClientSession csess) {
		this.csess = csess;
	}
	public void setClientId(int clientId) {
	}
	public int getClientVersion() {
		return clientVersion;
	}
	public int getGameId() {
		return gameId;
	}
	public String getWhereRegistered() {
		return whereRegistered;
	}
	public void setWhereRegistered(String whereRegistered) {
		this.whereRegistered = whereRegistered;
	}
    
}
